/***2024-12-16 迷途小羔羊
* 用于编写图集工具类
*/
namespace GYLite
{
    export class AtlasUtil
    {
        private static _callBack:(error:IAtlasError)=>void;
        private static _thisObj:any;
        /**下载图集
         * @param entries 图集文件列表
         * @param transprentCutting 是否裁切透明区域，默认true
         * @param combineAtlas 是否动作合并图集，默认false，不合并(当打包动作图集，每个动作将单独输出图集，将使用到分开的功能)
         * @param gap 小图间隙，默认1
         * @param maxSize 最大接受打入图集的图片，默认512
         * @param callBack 打包结束回调 默认null
         * @param thisObj 回调指向 默认null
         * @param isEffect 是否特效序列 默认false
         * @param savePath 保存路径，默认null
        */
        public static downloadAtlas(entries:FileSystemFileEntry[],transprentCutting:boolean=true,combineAtlas:boolean=false,gap:number=1,maxSize:number=512,callBack:(error:IAtlasError)=>void=null,thisObj:any=null,isEffect:boolean=false, savePath:string=null):void
        {
            let dict:{[key:string]:EntryData[]} = {};
            let count:number = 0;
            AtlasUtil._callBack = callBack;
            AtlasUtil._thisObj = thisObj;
            entries.forEach((entry:FileSystemFileEntry)=>{
                let arr2:string[], arr:string[] = entry.fullPath.split("/");
                let arr3:EntryData[];
                let entryData:EntryData;
                let name:string,key:string,texName:string,action:string;
                let dirName:string;
                let dirNum:number,direction:number;                
                arr.shift();                
                name = arr.pop();
                dirNum = arr.length;
                arr2 = name.split(".");
                if(arr.length > 0)
                {
                    if(dirNum > 2)//三级目录结构认为携带方向
                    {
                        dirName = arr[dirNum-2];
                        direction = Number(arr[dirNum-1]);
                        action = dirName;
                        texName = dirName + "_" + direction + "_" + arr2[0];//三级目录结构，文件夹的名字=二级文件夹名称_一级文件夹名称_文件名，一级目录直接用文件名
                    }
                    else
                    {
                        dirName = arr[dirNum-1];
                        action = dirNum > 1?dirName:"idle";
                        texName = dirNum > 1?dirName + "_" + arr2[0]:arr2[0];//二级目录结构，文件夹的名字=文件夹名称_文件名，一级目录直接用文件名
                    }                    
                    if(combineAtlas && arr.length > 1)
                        arr.pop();
                    key = arr.join("_");
                    if(dict[key] == null)
                        dict[key] = [];
                    arr3 = dict[key];
                    entryData = arr3[arr3.length] = {
                        entry:entry, 
                        key:key, 
                        res:null, 
                        name:arr2[0],
                        texName:texName, 
                        ext:arr2[1],
                        offX:0,
                        offY:0,
                        direction:direction,
                        textureWidth:0,
                        textureHeight:0,
                        sourceWidth:0,
                        sourceHeight:0,
                        combineAtlas:combineAtlas,
                        gap:gap,
                        cutting:transprentCutting,
                        maxSize:maxSize,
                        isEffect:isEffect,
                        resObj:null,
                        savePath:savePath
                    };       
                    if(action) 
                        entryData.action = action;
                    ++count;
                }
            });
            let loader:GYLoader = new GYLoader();
            for(var key in dict)
            {
                let arr:EntryData[] = dict[key];
                let i:number,len:number;
                let entryData:EntryData;
                len = arr.length;
                for(i=0;i<len;++i)
                {
                    entryData = arr[i];
                    (<FileSystemFileEntry>entryData.entry).file((function(file:Blob) {
                        let url:string = URL.createObjectURL(file);                        
                        loader.load(url, (loadInfo:GYLite.LoadInfo)=>{
                            let entryData:EntryData = loadInfo.param.obj;
                            --count;
                            if(loadInfo.hasRes())
                            {                                
                                entryData.resObj = loadInfo.content;
                                entryData.res = loadInfo.content.res;                                
                                //计算透明度偏移，除去透明度的宽高
                                if(entryData.cutting)
                                {
                                    entryData.sourceWidth = entryData.res.textureWidth;
                                    entryData.sourceHeight = entryData.res.textureHeight;                                    
                                    let outline:number[] = GYLite.PixelUtil.getRectOutline(entryData.res.getPixels(0,0,entryData.sourceWidth,entryData.sourceHeight),entryData.sourceWidth,entryData.sourceHeight);
                                    entryData.offX = outline[0];
                                    entryData.offY = outline[1];                                    
                                    entryData.textureWidth = outline[2] - outline[0];
                                    entryData.textureHeight = outline[7] - outline[1];
                                }
                                else
                                {
                                    entryData.offX = entryData.offY = 0;
                                    entryData.sourceWidth = entryData.textureWidth = entryData.res.textureWidth;
                                    entryData.sourceHeight = entryData.textureHeight = entryData.res.textureHeight;
                                }
                            }
                            if(count == 0)
                            {
                                AtlasUtil.outputAtlas(dict);
                            }
                        }, entryData, GYLite.LoadType.TYPE_IMAGE,"get", {obj:this},null);
                    }).bind(entryData), (e:DOMException)=>{
                        console.error(e.stack);
                    });
                }
            };
            
            
        }  
        private static outputAtlas(dict:{[key:string]:EntryData[]}):void
        {
            //根据文件生成图集
            let i:number,len:number;
            let rect:GYLite.AtlasRect;
            let atlasRect:GYLite.AtlasRect;
            let entryDatas:EntryData[];
            let entryData:EntryData;
            let atlasRects:GYLite.AtlasRect[] = [];
            for(var key in dict)
            {                                    
                entryDatas = dict[key];
                if(entryDatas.length > 0)
                {
                    //先把图片尺寸按从大到小排序
                    entryDatas.sort((a:EntryData,b:EntryData):number=>{
                        if(a.textureWidth+a.textureHeight > b.textureWidth+b.textureHeight)
                            return -1;
                        return 1;
                    });
                    //创建虚拟图集
                    atlasRect = new GYLite.AtlasRect(0,0,2048,2048,null,true);
                    atlasRect.atlasName = key + ".png";
                    len = entryDatas.length;
                    for(i=0;i<len;++i)
                    {
                        entryData = entryDatas[i];    
                        if(entryData.textureWidth > entryData.maxSize || entryData.textureHeight > entryData.maxSize)
                            continue;                    
                        rect = atlasRect.cutRect(entryData.textureWidth,entryData.textureHeight,GYLite.AtlasPlaceType.SQUARE,entryData.gap);
                        rect.sourceWidth = entryData.sourceWidth;
                        rect.sourceHeight = entryData.sourceHeight;
                        rect.offX = entryData.offX;
                        rect.offY = entryData.offY;
                        if(rect)
                        {
                            rect.texture = entryData.res;
                            rect.name = entryData.texName;
                        }
                        else
                        {
                            GYLite.SysError.ATLAS_INSERT_SIZE_LIMIT.throwError([entryData.key,entryData.texName,entryData.textureWidth,entryData.textureHeight])                                    
                        }
                    }                    
                    atlasRect.atlasMinResize();                                        
                    atlasRects[atlasRects.length] = atlasRect;
                }                                       
            }            
            //批量保存图集到本地
            GYLite.AtlasRect.outputAtlas(atlasRects, false, (result:GYLite.IOutputAtlasResult[])=>{
                result.forEach((obj:GYLite.IOutputAtlasResult)=>{                    
                    let n:string;
                    let json:any = obj.json;
                    let entryDatas:EntryData[];
                    let entryData:EntryData;
                    let actions:any;
                    let i:number,len:number;
                    let failList:string[] = [];
                    let msg:string;
                    let code:number=0;
                    let downloadName:string,key:string;
                    n = obj.json.file;
                    key = n.split(".")[0];
                    entryDatas = dict[key];
                    if(entryDatas[0] && entryDatas[0].isEffect)
                    {
                        downloadName = key + "_" + entryDatas.length + "_0.png";
                    }                        
                    else
                        downloadName = n;
                    // 附加其他参数，动作配置
                    json.meta = {};
                    json.meta.num = entryDatas.length;
                    json.meta.reduce = 1;
                    json.meta.src_num = entryDatas.length;
                    json.meta.scale = 1;
                    json.meta.frameWidth = entryDatas[0].sourceWidth;
                    json.meta.frameHeight = entryDatas[0].sourceHeight;	
                    json.meta.combineAtlas = entryDatas[0].combineAtlas;
                    if(json.meta.actions == null)
                        json.meta.actions = {};
                    actions = json.meta.actions;                    
                    len = entryDatas.length;
                    for(i=0;i<len;++i)
                    {
                        entryData = entryDatas[i]; 
                        if(entryData.textureWidth > entryData.maxSize || entryData.textureHeight > entryData.maxSize)
                        {
                            failList[failList.length] = entryData.key + "/" + entryData.name + "." + entryData.ext;                            
                        }
                        if(actions[entryData.action] == null)                        
                            actions[entryData.action] = {};                           
                        actions[entryData.action][entryData.direction][Number(entryData.name)] = entryData.texName;
                    }
                    //下载json和png
                    let api:any = window["API"];
                    if(api && entryData && entryData.savePath)
                    {
                        const pathSeparator = navigator.platform.indexOf('Win') == 0 ? '\\' : '/';
                        (<Blob>obj.blob).arrayBuffer().then((value:ArrayBuffer)=>{
                            api.writeFile(entryData.savePath + pathSeparator + downloadName, new Uint8Array(value));
                        });
                        api.writeFile(entryData.savePath + pathSeparator + downloadName.replace(".png",".json"), JSON.stringify(json));                        
                    }
                    else
                    {                        
                        DomUtil.browserSave(downloadName,obj.blob, {type:"image/png"});
                        DomUtil.browserSave(downloadName.replace(".png",".json"),JSON.stringify(json), {type:"text"});
                    }                    
                    //销毁内存占用
                    len = entryDatas.length;
                    for(i=0;i<len;++i)
                    {
                        entryData = entryDatas[i];
                        GYLite.GYLoader.deleteRes(entryData.resObj);
                    }
                    if(AtlasUtil._callBack!=null)
                    {
                        if(failList.length > 0)
                        {
                            msg = "存在尺寸过大无法打入图集!";
                            code = 1;
                        }                            
                        AtlasUtil._callBack.call(AtlasUtil._thisObj, {failList:failList,msg:msg,code:code});
                    }
                        
                });
            }, this); 
        }      
    }
    interface EntryData
    {
        /**拖拽的文件记录*/entry:FileSystemFileEntry;
        /**所属的图集key*/key:string;
        /**图集纹理*/res:egret.Texture;
        /**文件名称，如果是动作则为序列号*/name:string;
        /**图集里面的小图名字*/texName:string;
        /**拖拽的文件记录*/ext:string;
        /**透明像素偏移X*/offX:number;
        /**透明像素偏移Y*/offY:number;
        /**纹理宽度（排除透明像素）*/textureWidth:number;
        /**纹理高度（排除透明像素）*/textureHeight:number;
        /**纹理实际宽度*/sourceWidth:number;
        /**纹理实际高度*/sourceHeight:number;
        /**可入图集的最大尺寸*/maxSize:number;
        /**加载进来的图片资源引用*/resObj:GYLite.ResObject;     
        /**是否裁切透明像素*/cutting:boolean; 
        /**是否合并二级目录的图片到一张图集*/
        combineAtlas:boolean;
        /**图集小图的间隙*/gap:number;
        /**图集的动作名称（如果是动作图集）*/action?:string;
        /**是否特效序列*/isEffect?:boolean;
        /**保存路径*/savePath?:string;
        /**朝向0-7*/direction?:number;
    }
    export interface IAtlasError
    {
        /**错误的文件列表*/failList:string[];
        /**错误信息*/msg:string;
        /**0为正常，无错误，其他情况为错误码*/code:number;
    }
}